package com.shinewind.payment.controller;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shinewind.common.config.alipay.properties.AliPayProperties;
import com.shinewind.common.constant.messageConstant;
import com.shinewind.info.service.IModelCommentService;
import com.shinewind.info.service.IUserInfoService;
import com.shinewind.payment.service.IRelateGoodsService;
import com.shinewind.payment.service.ISuccessOrderService;
import com.shinewind.payment.service.IUserAddressService;
import com.shinewind.payment.service.IWaitOrderService;
import com.shinewind.pojo.dto.*;
import com.shinewind.pojo.entity.RelateGoods;
import com.shinewind.pojo.entity.SuccessOrder;
import com.shinewind.pojo.entity.UserAddress;
import com.shinewind.pojo.entity.WaitOrder;
import com.shinewind.pojo.result.Result;
import com.shinewind.pojo.vo.CartVo;
import com.shinewind.pojo.vo.PageVo;
import com.shinewind.pojo.vo.UserAddressVo;
import com.shinewind.pojo.vo.WaitOrderVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/payment")
@Api(value = "订单支付接口",description = "支付订单信息")
public class PayOrderController {
    @Autowired
    private IUserAddressService iUserAddressService;
    @DubboReference
    private IUserInfoService iUserInfoService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired(required = false)
    private AlipayClient alipayClient;
    @Autowired(required = false)
    private AlipayTradePagePayRequest alipayRequest;
    @Autowired(required = false)
    private AliPayProperties aliPayProperties;
    @Autowired
    private ISuccessOrderService iSuccessOrderService;
    @Autowired
    private IRelateGoodsService iRelateGoodsService;
    @Autowired
    private IWaitOrderService iWaitOrderService;

    @GetMapping("/userInfo/address/{uId}")
    public Result getUserAddressByUid(@PathVariable("uId") String uId){
        //查询用户收货地址
        List<UserAddress> userAddresses = iUserAddressService.getUserAddressByUid(uId);
        List<UserAddressVo> userAddressVos = userAddresses.stream().map(userAddress -> {
            UserAddressVo userAddressVo = UserAddressVo.builder().build();
            BeanUtils.copyProperties(userAddress,userAddressVo);
            return userAddressVo;
        }).collect(Collectors.toList());
        if(userAddressVos.size() > 0){
            return Result.success(userAddressVos, BooleanUtil.isTrue(userAddressVos.size()>0),
                    messageConstant.QUERY_SUCCESS);
        }
        else{
            return Result.fail(BooleanUtil.isTrue(userAddressVos.size()>0),
                    messageConstant.QUERY_NULL);
        }
    }

    @PostMapping("/add/address/{uId}")
    public Result insertUserAddressByuId(@PathVariable("uId") String uId,@RequestBody UserAddressDto userAddressDto){
        Boolean flag = iUserAddressService.saveUserAddressByuId(uId,userAddressDto);
        if(flag){
            return Result.success(true, messageConstant.INSERT_SUCCESS);
        }
        else{
            return Result.fail(false,messageConstant.INSERT_ERROR);
        }
    }

    @PostMapping("/update/address/{addressId}")
    public Result updateUserAddressByaddressId(@PathVariable("addressId") String addressId,@RequestBody UserAddressDto userAddressDto){
        Boolean flag = iUserAddressService.updateUserAddressByaddressId(addressId,userAddressDto);
        if(flag){
            return Result.success(true, messageConstant.UPDATE_SUCCESS);
        }
        else{
            return Result.fail(false,messageConstant.UPDATE_ERROR);
        }
    }

    @PutMapping("/update/default/{addressId}")
    public Result updateDefaultAddressByaddressId(@PathVariable("addressId") String addressId){
        System.out.println("addressId:"+addressId);
        Boolean flag = iUserAddressService.updateDefaultAddressByaddressId(addressId);
        if(flag){
            return Result.success(true, messageConstant.UPDATE_SUCCESS);
        }
        else{
            return Result.fail(false,messageConstant.UPDATE_ERROR);
        }
    }

    @DeleteMapping("/delete/address/{addressId}")
    public Result deleteAddressByaddressId(@PathVariable("addressId") String addressId){
        Boolean flag = iUserAddressService.deleteAddressByaddressId(addressId);
        if(flag){
            return Result.success(true, messageConstant.DELETE_SUCCESS);
        }
        else{
            return Result.fail(false,messageConstant.DELETE_ERROR);
        }
    }

    @PostMapping("/add/goods/{uId}")
    public Result insertGoodsByuId(@PathVariable("uId") String uId, @RequestBody List<CartVo> detailInfo){
        String orderId = UUID.randomUUID().toString().replace("-","");
        System.out.println("detailInfo:"+detailInfo);
        redisTemplate.opsForList().leftPushAll(orderId,detailInfo);
        if(redisTemplate.hasKey(orderId)){
            return Result.success(orderId,true, messageConstant.INSERT_SUCCESS);
        }
        else
            return Result.fail(false,messageConstant.INSERT_ERROR);
    }

    @GetMapping("/goods/list/{uId}/{orderId}")
    public Result getOrderGoodsListByUid(@PathVariable("uId") String uId,@PathVariable("orderId") String orderId){
        //按照当前的订单id和用户id从redis中读取商品列表信息
        List<CartVo> goodsList = redisTemplate.opsForList().range(orderId,0,-1);
        System.out.println("goodsList:"+goodsList);
        if(goodsList.size()>0){
            return Result.success(goodsList, BooleanUtil.isTrue(goodsList.size()>0),
                    messageConstant.QUERY_SUCCESS);
        }
        else if(goodsList.size() == 0){
            return Result.fail(false,messageConstant.QUERY_ERROR);
        }
        return Result.fail(false,messageConstant.QUERY_ERROR);
    }

    @PostMapping("/order/success/{uId}/{orderId}")
    public Result insertSuccessOrder(@PathVariable("uId") String uId,@PathVariable("orderId") String orderId){
        //将订单信息加入成功表
        Boolean flag = iSuccessOrderService.saveSuccessOrderByUidANDOrderID(uId,orderId);
        if(flag){
            //按照当前的订单id从redis中读取商品列表信息
            List<CartVo> goodsList = redisTemplate.opsForList().range(orderId,0,-1);
            //批量在商品关联表中写入信息
            Boolean result = iRelateGoodsService.saveByListANDOrderId(orderId,goodsList);
            if(result){
                return Result.success(true, messageConstant.INSERT_SUCCESS);
            }
            else{
                return Result.fail(false,messageConstant.INSERT_ERROR);
            }
        }
        else{
            return Result.fail(false,messageConstant.INSERT_ERROR);
        }
    }
    //创建未支付订单
    @PostMapping("/order/wait/add/{uId}/{orderId}")
    public Result addWaitOrder(@PathVariable("uId") String uId,@PathVariable("orderId") String orderId){
        Boolean flag = iWaitOrderService.saveWaitOrderByUidANDOrderId(uId,orderId);
        if(flag){
            return Result.success(true, messageConstant.INSERT_SUCCESS);
        }
        else{
            return Result.fail(false,messageConstant.INSERT_ERROR);
        }
    }
    //查询该用户未支付订单列表
    @PostMapping("/wait/order/list/{uId}")
    public PageVo<WaitOrderVo> waitPayOrderList(@PathVariable("uId") String uId, @RequestBody PageDto pageDto){
        System.out.println("uId:"+uId);
        //根据用户id从数据库中搜索该用户未支付订单号集合列表
        List<String> waitOrderList = iWaitOrderService.getWaitOrderByUid(uId);
        System.out.println("waitOrderList:"+waitOrderList.stream().findFirst().get());
        //有未支付的订单
        if(waitOrderList.stream().findFirst().get().equals("没有未支付的订单")){
            return new PageVo<WaitOrderVo>(null,false,messageConstant.QUERY_SUCCESS,0);
        }
        else{
            //从redis中查询相关的信息
            List<WaitOrderVo> waitOrderVos = iWaitOrderService.getRelateInfoByRedis(waitOrderList);
            //分页返回列表
            Integer total = waitOrderVos.size();
            waitOrderVos = ListUtil.page(pageDto.getCurrentPage()-1,pageDto.getPageSize(),waitOrderVos);
            return new PageVo<WaitOrderVo>(waitOrderVos,BooleanUtil.isTrue(waitOrderVos.size() > 0)
                    ,messageConstant.QUERY_SUCCESS,total);
        }
    }

    @PostMapping("/order/pay/{uId}")
    public Result payOrderByUidAndOrderId(@PathVariable("uId") String uId,HttpServletRequest req,
                                          @RequestBody OrderDto orderDto) throws AlipayApiException, JsonProcessingException {
        orderDto.setProduct_code("FAST_INSTANT_TRADE_PAY");
        //请求支付宝进行付款,获取支付结果
        System.out.println("orderDto:"+orderDto);
        System.out.println("alipayClient:"+alipayClient);
        //将订单相关信息放入content
        String BizContent = new ObjectMapper().writeValueAsString(orderDto);
        alipayRequest.setBizContent(BizContent);
        alipayRequest.setReturnUrl(aliPayProperties.getReturn_url());
        alipayRequest.setNotifyUrl(aliPayProperties.getNotify_url());
        System.out.println(alipayRequest.getBizContent());
        String resultPage = alipayClient.pageExecute(alipayRequest).getBody();
        System.out.println("resultPage:"+resultPage);
        if(StrUtil.isNotBlank(resultPage)){
            req.setAttribute("uId",uId);
            return Result.success(resultPage, true,messageConstant.Pay_SUCCESS);
        }
        else{
            return Result.fail(false,messageConstant.Pay_ERROR);
        }
    }
    //支付宝异步通知
    @PostMapping("/order/result/notifyUrl")
    @Transactional
    public String getNotifyUrl(HttpServletRequest req) throws JsonProcessingException, AlipayApiException {
        String tradeStatus = req.getParameter("trade_status"); // 交易状态
        String orderNo = req.getParameter("out_trade_no"); // 获取订单号
        String tradeNo = req.getParameter("trade_no"); // 支付宝交易凭证号
        Map<String,String> params = new HashMap<>();
        Map<String,String[]>  requestParams = req.getParameterMap();
        for(Iterator<String> iterator = requestParams.keySet().iterator();iterator.hasNext();){
            String key = iterator.next();
            String[] values = requestParams.get(key);
            String formatValues = "";
            for(int i=0;i< values.length;i++){
                //如果是最后一项就省去逗号
                formatValues = (i == values.length-1) ? formatValues + values[i] : formatValues + values[i] + ",";
            }
            params.put(key,formatValues);
        }
        System.out.println("params:"+params);
        Boolean signFlag = AlipaySignature.rsaCheckV1(params,aliPayProperties.getAlipay_public_key(),
                aliPayProperties.getCharset(),aliPayProperties.getSign_type());
        System.out.println("result:"+signFlag);
        //如果验签成功
        if(signFlag == true){
            if(tradeStatus.equals("TRADE_SUCCESS")){
                //TODO 操作事务
                //获取订单号
                String out_trade_no = req.getParameter("out_trade_no");
                //订单成功的时间
                String gmt_payment = req.getParameter("gmt_payment");
                //该笔订单的收货id
                String passback_params = req.getParameter("passback_params");
                //用户id
                String uId = (String) req.getAttribute("uId");
                SuccessOrder successOrder = SuccessOrder.builder().orderId(out_trade_no)
                        .createTime(DateUtil.parse(gmt_payment,"yyyy-MM-dd HH:mm:ss"))
                        .addressId(passback_params)
                        .uId(iUserAddressService.getUidByAddressId(passback_params))
                        .build();
                //将付款后的信息写入成功表
                Boolean flag = iSuccessOrderService.save(successOrder);
                System.out.println("flag:"+flag);
                //从redis中读取相关商品并写入订单商品表
                List<CartVo> goodsList = redisTemplate.opsForList().range(out_trade_no,0,-1);
                List<RelateGoods> relateGoodsList = goodsList.stream().map(good ->{
                    RelateGoods relateGoods = RelateGoods.builder().build();
                    BeanUtils.copyProperties(good,relateGoods);
                    relateGoods.setOrderId(out_trade_no);
                    relateGoods.setMId(good.getMId());
                    return relateGoods;
                }).collect(Collectors.toList());
                Boolean flag2 = iRelateGoodsService.saveBatch(relateGoodsList);
                System.out.println("flag2:"+flag2);
                System.out.println("relateGoodsList:"+relateGoodsList);
                if(flag && flag2){
                    //两张表数据都已经写入成功,查看wait表是否还存在
                    if(iWaitOrderService.isExistInWaitOrder(out_trade_no) > 0){
                        //存在，删除
                        Boolean flag3 = iWaitOrderService.deleteWaitOrderByOrderId(out_trade_no);
                        //删除redis中缓存的订单商品
                        if(flag3){
                            System.out.println("s1");
                            redisTemplate.delete(out_trade_no);
                            //redisTemplate.opsForList().remove(out_trade_no,0,-1);
                        }
                        return "success";
                    }
                    else{
                        //表中没有，但是redis的缓存还在
                        System.out.println("s2");
                        redisTemplate.delete(out_trade_no);
                        //redisTemplate.opsForList().remove(out_trade_no,0,-1);
                        return "success";
                    }
                }
                else{
                    System.out.println("f1");
                    return "failed";
                }
            }
        }
        else{
            //TODO 失败
            return "failed";
        }
        return tradeStatus;
    }

    @PostMapping("/good/shopping/comment")
    @ApiOperation(value = "添加评论",notes = "添加评论",response = Result.class)
    public Result addParentComment(@RequestBody ModelCommentDto modelCommentDto){
        System.out.println("modelCommentDto:"+modelCommentDto);
        Boolean flag = iSuccessOrderService.saveCommentByDto(modelCommentDto);
        if(flag)
            return Result.success(true,
                    messageConstant.INSERT_SUCCESS);
        else
            return Result.fail(false,messageConstant.INSERT_ERROR);
    }

    @PutMapping("/good/comment/delete")
    @ApiOperation(value = "删除评论",notes = "删除评论",response = Result.class)
    public Result deleteComment(@RequestBody ModelCommentDeleteDto modelCommentDeleteDto){
        System.out.println("modelCommentDeleteDto:"+modelCommentDeleteDto);
        Boolean flag = iSuccessOrderService.deleteCommentByDto(modelCommentDeleteDto);
        if(flag)
            return Result.success(true,
                    messageConstant.DELETE_SUCCESS);
        else
            return Result.fail(false,messageConstant.DELETE_ERROR);
    }

    @DeleteMapping("/wait/order/cancel/{orderId}")
    @ApiOperation(value = "取消待支付订单",notes = "取消待支付订单",response = Result.class)
    public Result cancelWaitOrder(@PathVariable("orderId") String orderId){
        Boolean flag = iWaitOrderService.cancelWaitOrderByOrderId(orderId);
        if(flag){
            redisTemplate.delete(orderId);
            return Result.success(true,
                    messageConstant.DELETE_SUCCESS);
        }
        else{
            return Result.fail(false,messageConstant.DELETE_ERROR);
        }
    }
}